Asp.net core 身份认证框架 Microsoft Identity的使用以及如何使用Idengtity创建自带的用户模型SignInManager和UserManager的使用等等

您所在的位置:网站首页 jwt identity字段 Asp.net core 身份认证框架 Microsoft Identity的使用以及如何使用Idengtity创建自带的用户模型SignInManager和UserManager的使用等等

Asp.net core 身份认证框架 Microsoft Identity的使用以及如何使用Idengtity创建自带的用户模型SignInManager和UserManager的使用等等

2024-07-11 16:10| 来源: 网络整理| 查看: 265

要启动身份认证组件,首先要更改数据库上下文中继承的关系,原本我们是继承于在这里插入图片描述 Dbcontext这个类,现在我们需要继承IdentityDbContext 继承这个类,我们需要安装对应的框架, 如图: 在这里插入图片描述 这里注意,版本一定要和你.net core 框架版本一致,不然不匹配。 框架安装完成后,我们进入数据库上下文类引入框架。 在这里插入图片描述 接着,将DbContext替换为IdentityDbContext 在这里插入图片描述 其中IdentityDbContext里的泛型IdentityUser就是身份认证的数据库结构,相当于UserModel也就是用户模型,里面有自定义好的相关用户信息字段。比如ID,姓名,性别什么的。这些定义都是由.net core 自动完成的,也会映射到数据库中。有了数据库结构后,IdentityDbContext会自动为我们的系统添加与用户表相对应的映射关系,如果数据库的用户表,UserTable还不存在,IdentityDbContext可以帮我们更新数据库,自动为我们添加用户表,这样通过数据库上下文对象,我们系统就可以自动获取到用户的信息了。而我们不需要为实现用户模块写一丁点代码。

对于IdentityUser如果默认结构不能满足你的需求,你也可以通过继承IdentityUser去修改用户模型。 补充点:记得初始化构造函数

public AppDBcontext(DbContextOptions options) : base(options) { }

好了,接着 在创建数据库之前,我们需要给框架注册服务认证的依赖。 我们找到Startup.cs文件 在ConfigureServices这个函数中添加函数依赖,代码如下:

///注册身份认证的服务依赖 ///泛型俩个参数分别是用户数据模型和角色模型 ///AddEntityFrameworkStores 通过这个函数连接数据库上下文对象 泛型为对应的上下文对象。 services.AddIdentity().AddEntityFrameworkStores();

框架注入成功后,我们来进行数据更新。 这里使用.net 的命令进行数据迁移,不会数据迁移的请看这篇文章 在项目根目录下 进行CMD 输入一下命令 进行数据迁移 在这里插入图片描述 执行完成后我们可以在项目中看到对应的项目迁移代码。 在这里插入图片描述 我们可以在代码中的UP函数中看到,代码自动编写了大概创建了八张表。可能很多人有疑问了,我明明没有添加这些表,为什么系统给我加了这么多乱七八糟的表呢, 我们打开数据库上下文,其实就是因为你继承了IdentityDbContext所以也就继承了IdentityDbContext自带的数据模型,以及数据模型所对应的数据库表,接下来让我回到命令行,执行更新数据库。 在这里插入图片描述 输入红线代码进行数据库更新。 执行完成后我们可以去数据库看到更新的表 在这里插入图片描述 这些表就是我们用户模块的新表。现在项目的用户数据就创建完成了。

接着我们试着用这写数据库,做一个注册功能。

首先创建一个接收注册消息的Dto

using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.ComponentModel.DataAnnotations; namespace Fakexiecheng.API.Dtos { public class RegisterDto { [Required]//Required注释 为必填字段 public string Email { get; set; } [Required] public string Password { get; set; } [Required] [Compare(nameof(Password),ErrorMessage ="输入的密码不一致")] public string CofirmPassword { get; set; } } }

接着我们在对应的Api里写好对应的注册函数

private readonly UserManager _userManager;//可以通过这个工具对密码进行加密 泛型为定义的用户模型 /// /// 用户注册 /// /// 注册信息 /// [AllowAnonymous] [HttpPost("register")] public async Task Register([FromBody] RegisterDto registerDto) { //1 使用用户名创建用户对象 var user = new IdentityUser() { UserName = registerDto.Email, Email = registerDto.Email }; //2 hash密码,保存用户 var result = await _userManager.CreateAsync(user, registerDto.Password);//hash密码并连同用户模型对象 一起保存打数据库中 //如果成功表示 用户创建成功并且保存起来了 //不成功 if (!result.Succeeded) { //返回400 return BadRequest(); } //3 return //成功 200 return Ok(); }

其中hash密码的时候,我们用的Identity自带的工具 UserManager。代码中都有注释 自己看吧, 接着我们来试着用Postman进行请求一下。 在这里插入图片描述 可以看到没什么问题,而且UserManager可以帮你自动把用户名是否相同的验证都做了,就是CreateAsync用它哈希加密后 貌似不能解密。可能我没找到方法吧,而且UserManager对密码做的有限制,看我上面图密码搞那么复杂 你应该就懂了,太简单,是无法注册的。。。内部是如何验证的我也不知道,,,这个还等着网友们去探秘。可以下载微软自己提供的反编译工具,叫什么来着 ,忘记了,自己可以看看CreateAsync这个方法的内部结构,相信你可以找到答案,,,

接着把数据库接入登录系统中

首先用Identity框架下的SignInManager来处理用户登录验证,同时使用UserManager获取用户信息,并且提取用户权限,并转换为Claim使用JWT输出。 首先我们在控制器中注入服务依赖。 在这里插入图片描述 添加划线的代码,.net core 服务注入都是通过构造函数实现的,这个我想大家都知道吧。

接下来我们使用SignInManager来进行用户验证, 登录方法中加入一下代码:

[AllowAnonymous]//允许所有人访问 [HttpPost("login")] public async Task login([FromBody] LoginDto loginDto) { //1.进行信息认证 var loginResult = await _signInManager.PasswordSignInAsync(loginDto.Email,loginDto.password , false //指示在关闭浏览器后登录 Cookie 是否应该保留的标志。 , false//多次登录失败后 是否锁定账号 ); //判断是否验证成功 if (!loginResult.Succeeded) { // 400 return BadRequest(); } //获取用户信息 var user = await _userManager.FindByNameAsync(loginDto.Email); //2.创建JWT Token //header singningAlgorithm储存编码算法 var singningAlgorithm = SecurityAlgorithms.HmacSha256; //payload 需要用到的数据 var claims = new List { // sub ==jwt的ID //等同于 Sub:fake_user_id new Claim(JwtRegisteredClaimNames.Sub,user.Id), // new Claim(ClaimTypes.Role,"Admin")//角色信息 }; //获取用户角色 var roleNames = await _userManager.GetRolesAsync(user); //遍历角色 一个用户可能有多个角色 foreach (var roleName in roleNames) { var roleClaim = new Claim(ClaimTypes.Role, roleName); claims.Add(roleClaim); } //signature 数字签名 需要用到私钥 //私钥一般放在配置文件中 私钥是自定义的 想写什么写什么 //使用utf进行编码 var secretByte = Encoding.UTF8.GetBytes(_configuration["Authentication:SecretKey"]); //使用非对称算法 对私钥加密 var signingkey = new SymmetricSecurityKey(secretByte); //通过256验证非对称加密的私钥 var signingCredentials = new SigningCredentials(signingkey, singningAlgorithm); //创建token var token = new JwtSecurityToken( issuer:_configuration ["Authentication:Issuer"],//谁发布的TOken audience:_configuration["Authentication:Audience"],//token发布给谁 claims,//payload数据 notBefore:DateTime.UtcNow,//发布时间 expires:DateTime.UtcNow.AddDays(1),//有效时间 signingCredentials//数字签名 ); //以字符串形式 输出Token var tokenStr = new JwtSecurityTokenHandler().WriteToken(token); //3.返回jwt字符串 return Ok(tokenStr); }

接下来我们来postman测试一下。 首先注册用户 在这里插入图片描述

然后用注册的用户登录系统 在这里插入图片描述

然后通过返回的JWT来进行一下数据访问 在这里插入图片描述

我们发现404 其实这里有个天大的坑。 原因:在我们使用Identity框架的多角色验证时,验证中间件使用的并不是JWT验证,和默认验证并不匹配。 解决办法 显示指定使用JWT 的验证方式。 再要访问的所有需要权限认证方法头部加上一下代码:

[Authorize(AuthenticationSchemes = "Bearer")]

接着测试一下 在这里插入图片描述 这下可以看到 返回403权限不足而不是404了 这是因为我规定了只有管理员才可以创建东西。所以这是正确的。

接着我们来定制一下用户模型

场景:当我们用的默认用户模型字段不够的时候,我么可以通过继承来定制一个用户模型。比如下图中 在这里插入图片描述 自带的这些字段不够用呢,就可以通过定制来扩展、

我们来看看数据库结构

表示用户模型 在这里插入图片描述 用于保存直接与用户权限绑定的声明,比如只允许张三可以删除数据。 在这里插入图片描述 用于第三方登录工具,比如记录微信登录的信息。 在这里插入图片描述 用于保存用户角色信息,一个用户可能有多个角色 在这里插入图片描述 记录用户登录的session,比如登录时长,拉黑用户都在这个表记录。

接着我们从代码的角度重载一下这几张表,首先新建一个ApplicationUser类继承IdentityUser,然后添加一下代码,这里切记 代码一定要一致,因为名称要和父类名称一致,不然会失败。

using Microsoft.AspNetCore.Identity; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Fakexiecheng.API.Models { public class ApplicationUser:IdentityUser { public string Address { get; set; } //shoppingCart //orders public virtual ICollection UserRoles { get; set; } public virtual ICollection Claims { get; set; } public virtual ICollection Logins { get; set; } public virtual ICollection Tokens { get; set; } } }

然后我们把用到的IdentityUser全部替换为ApplicationUser

接着我们可以注入一下种子数据进行数据的更新、 接着我进入上下文关系文档,在OnModelCreating函数中进行种子数据的初始化。 添加如下代码:

//初始化用户与角色的种子数据 //1.更新用户与角色的外键 //HasMany 表示一对多的关系 这个关系可以被映射为roles 每一个role都有一个外键关系 WithOne 而这个外键关系使用的是UserID 这个ID是必须的 所以加上IsRequired() modelBuilder.Entity(u => u.HasMany(x => x.UserRoles).WithOne().HasForeignKey(ur => ur.UserId).IsRequired()); //2.添加管理员角色 //给角色添加主键 var adminRoleId = Guid.NewGuid().ToString(); modelBuilder.Entity().HasData( new IdentityRole() { Id = adminRoleId, Name = "Admin", NormalizedName = "Admin".ToUpper()//大写 } ); //3.添加用户 var adminUserID = Guid.NewGuid().ToString(); ApplicationUser adminUser = new ApplicationUser { Id = adminUserID, UserName = "[email protected]", NormalizedUserName = "[email protected]".ToUpper(), Email= "[email protected]", NormalizedEmail= "[email protected]".ToUpper(), TwoFactorEnabled=false, EmailConfirmed=true, PhoneNumber="1234567891", PhoneNumberConfirmed=false }; //hash密码 var ph = new PasswordHasher(); adminUser.PasswordHash = ph.HashPassword(adminUser, "Fake123$"); modelBuilder.Entity().HasData(adminUser); //4.给用户加入管理员角色 modelBuilder.Entity().HasData(new IdentityUserRole(){ RoleId=adminRoleId, UserId=adminUserID });

然后我们进行数据迁移。 在这里插入图片描述 然后我们去数据迁移文件里解读一下代码 在这里插入图片描述 我们可以看到 ,添加了对应的数据和字段。 接着我们去用一下我们的种子数据。 在这里插入图片描述

在这里插入图片描述

我们发现可以成功登录并且创建数据。好了 就更新这么多了。。。。写的有点乱,希望不要介意。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3